package com.fsl.springbootdesignpattern.d_proxy.CustomProxy;


import javax.tools.JavaCompiler;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;

/**
 * @author dell
 */
public class MyProxy {

    public static final String ln = "\r\n";

    //获取反射的实例
    public static Object newProxyInstance(MyClassLoader loader,
                                          Class<?>[] interfaces,
                                          MyInvocationHandler h)
            throws IllegalArgumentException {

        FileWriter fw = null;
        try {
            //第一步：生成源代码,在这里为了简化，只保留第一个接口的信息，因为类只能单extends，但是可以多implements
            String code = generatorCode(interfaces[0]);

            //第二步：将生成的源代码输出到磁盘，保存为.java文件
            String filePath = MyProxy.class.getResource("").getPath();
            System.out.println(filePath);
            File f = new File(filePath + "$Proxy0.java");
            fw = new FileWriter(f);
            fw.write(code);
            fw.flush();
            fw.close();

            //第三步：编译源代码，并且生成.class文件
            JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
            StandardJavaFileManager m = compiler.getStandardFileManager(null, null, null);
            Iterable iterable = m.getJavaFileObjects(f);
            JavaCompiler.CompilationTask task = compiler.getTask(null, m, null, null, null, iterable);
            task.call();
            m.close();
            //第四步：将class文件中的内容，动态加载到JVM中来
            Class proxyClass = loader.findClass("$Proxy0");
            Constructor constructor = proxyClass.getConstructor(MyInvocationHandler.class);
            f.delete();
            //第五步：返回被代理后的代理对象
            return constructor.newInstance(h);
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            if(null != fw){
                try {
                    fw.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return null;
    }


    private static String generatorCode(Class<?> interfaces){
        // 使用代码的方式写完整的构建一个类
        StringBuilder sb = new StringBuilder();
                //包名
        sb.append("package com.fsl.springbootjunit.customproxy;").append(ln)
                //引入的反射包
          .append("import java.lang.reflect.Method;").append(ln)
                //类名设置为$Proxy0
          .append("public class $Proxy0 implements ").append(interfaces.getName()).append("{").append(ln)
                //变量MyInvocationHandler
          .append("MyInvocationHandler h;").append(ln)
                //构造方法，设置MyInvocationHandler
          .append("public $Proxy0(MyInvocationHandler h) {").append(ln)
          .append("this.h = h;").append(ln)
          .append("}");
                //通过反射获取代理接口的所有方法并激活

        for(Method m : interfaces.getMethods()){
            sb.append("public ").append(m.getReturnType()).append(" ").append(m.getName()).append("(){").append(ln)
              .append("try{")
              .append("Method m = " + interfaces.getName() + ".class.getMethod(\"" +m.getName()+"\",new Class[]{});")
              .append(ln)
              .append("this.h.invoke(this,m,null);").append(ln)
              .append("}").append("catch(Throwable e){e.printStackTrace();}").append(ln)
              .append("}");
        }
            sb.append("}");

        return sb.toString();
    }
}
